﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Codeplex.Data;
using System.Globalization;

namespace nanobot {

    public static class POLONIEXcom {

        public class OrderBook {
            public twoThings[] asks;
            public twoThings[] bids;
            public string isFrozen;
        }

        public class twoThings {
            public string Price;
            public string Amount;

        }

        public static string API_Public_Key { get; set; }
        public static string API_Private_Key { get; set; }
        public static string API_KEY_registry_key  = "poloniex_API_KEY";
        public static string API_Private_KEY_registry_key  = "poloniex_API_Private_KEY";

        public static string[] Pairs { get; private set; }
        public static Dictionary<string, List<string[]>> Ticker { get; private set; }
        public static List<string[]> OrderBooks_Asks { get; private set; }
        public static List<string[]> OrderBooks_Bids { get; private set; }
        public static string OrderBooks_isFrozen { get; private set; }
        public static List<string[]> Currencies { get; private set; }
        public static List<string[]> Balances { get; private set; }
        public static List<string[]> CompleteBalances { get; private set; }
        public static List<string[]> DepositAddresses { get; private set; }
        public static List<string[]> OpenOrders { get; private set; }
        public static List<string[]> TradeHistory_my { get; private set; }
        public static List<string[]> TradeHistory { get; private set; }
        public static List<string[]> ChartData { get; private set; }
        public static List<string[]> Deposits { get; private set; }
        public static List<string[]> Withdrawals { get; private set; }
        public static string NewAddress { get; private set; }
        public static int OrderNumber { get; private set; }
        public static string Error { get; private set; }
        public static string Response { get; private set; }

        // Boolean Values
        public static volatile bool is_FirstTime;
        public static volatile bool is_ReturnTicker_done;
        public static volatile bool is_ReturnOrderBook_done;
        public static volatile bool is_ReturnTradeHistory_done;
        public static volatile bool is_ReturnChartData_done;
        public static volatile bool is_ReturnCurrencies_done;
        public static volatile bool is_ReturnBalances_done;
        public static volatile bool is_ReturnCompleteBalances_done;
        public static volatile bool is_ReturnDepositAddresses_done;
        public static volatile bool is_GenerateNewAddress_done;
        public static volatile bool is_ReturnDepositsWithdrawals_done;
        public static volatile bool is_ReturnOpenOrders_done;
        public static volatile bool is_ReturnTradeHistory_my_done;
        public static volatile bool is_Buy_done;
        public static volatile bool is_Sell_done;
        public static volatile bool is_CancelOrder_done;
        public static volatile bool is_Withdraw_done;


        static POLONIEXcom () {
            is_FirstTime = true;
            is_ReturnTicker_done = true;
            is_ReturnOrderBook_done = true;
            is_ReturnTradeHistory_done = true;
            is_ReturnChartData_done = true;
            is_ReturnCurrencies_done = true;
            is_ReturnBalances_done = true;
            is_ReturnCompleteBalances_done = true;
            is_ReturnDepositAddresses_done = true;
            is_ReturnDepositsWithdrawals_done = true;
            is_ReturnOpenOrders_done = true;
            is_ReturnTradeHistory_my_done = true;
            is_GenerateNewAddress_done = true;
            is_Buy_done = true;
            is_Sell_done = true;
            is_CancelOrder_done = true;
            is_Withdraw_done = true;

            API_Public_Key = ModifyRegistry.Read( API_KEY_registry_key );
            API_Private_Key = ModifyRegistry.Read( API_Private_KEY_registry_key );

        }

        public static void ReturnTicker () {
            if ( !is_ReturnTicker_done ) {
                return;
            }
            is_ReturnTicker_done = false;

            Public_Query_Async( "returnTicker" );

        }
        private static void _ReturnTicker ( string result ) {
            Ticker = new Dictionary<string, List<string[]>>();

            dynamic [] json = ( dynamic[] ) DynamicJson.Parse( result );
            dynamic [] json2;
            List<string[]> temp;

            for ( int i = 0; i < json.Length; i++ ) {
                json2 = ( dynamic[] ) json[i].Value;
                temp = new List<string[]>();
                for ( int j = 0; j < json2.Length; j++ ) {
                    temp.Add( new string[]{
                                json2[j].Key, 
                                json2[j].Value
                            }
                    );

                }

                Ticker.Add( json[i].Key, temp );

            }

            Pairs = Ticker.Keys.ToArray();

        }

        public static void ReturnOrderBook ( string currencyPair, int depth = 50 ) {
            if ( !is_ReturnOrderBook_done ) {
                return;
            }
            is_ReturnOrderBook_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currencyPair"] = currencyPair;
            parameters["depth"] = depth;

            Public_Query_Async( "returnOrderBook", parameters );


        }
        private static void _ReturnOrderBook ( string result ) {
            OrderBooks_Asks = new List<string[]>();
            OrderBooks_Bids = new List<string[]>();
            Error = string.Empty;

            dynamic json = ( dynamic ) DynamicJson.Parse( result );

            if ( json.error() ) {
                Error = json.error;
                return;
            }

            foreach ( var ask in json.asks ) {
                OrderBooks_Asks.Add( new string[]{
                        ask[0],
                        ask[1].ToString( new CultureInfo( "en-us" ) )
                    }
                );


            }

            foreach ( var bid in json.bids ) {
                OrderBooks_Bids.Add(
                    new string[]{
                        bid[0],
                        bid[1].ToString( new CultureInfo( "en-us" ) )
                    }
                );

            }

            OrderBooks_isFrozen = json.isFrozen;



        }

        public static void ReturnTradeHistory ( string currencyPair, long startDate, long endDate ) {
            if ( !is_ReturnTradeHistory_done ) {
                return;
            }
            is_ReturnTradeHistory_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currencyPair"] = currencyPair;
            parameters["start"] = startDate;
            parameters["end"] = endDate;

            Public_Query_Async( "returnTradeHistory", parameters );

        }
        private static void _ReturnTradeHistory ( string result ) {
            dynamic j = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;

            if ( j.error() ) {
                Error = j.error;
                return;
            }

            dynamic [] json = ( dynamic[] ) DynamicJson.Parse( result );
            TradeHistory = new List<string[]>();
            

            foreach ( var item in json ) {
                TradeHistory.Add(
                    new string[]{
                        item.amount,
                        item.date,
                        item.rate,
                        item.total,
                        ( ( int ) item.tradeID ).ToString(),
                        item.type
                    }
                );
            }


        }

        /// <summary>
        /// period: 300, 900, 1800, 7200, 14400, and 86400
        /// </summary>
        /// <param name="currencyPair"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="period"></param>
        public static void ReturnChartData ( string currencyPair, long start, string period = "14400", long end = 9999999999 ) {
            if ( !is_ReturnChartData_done ) {
                return;
            }

            is_ReturnChartData_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currencyPair"] = currencyPair;
            parameters["start"] = start;
            parameters["end"] = end;
            parameters["period"] = period;

            Public_Query_Async( "returnChartData", parameters );

        }
        private static void _ReturnChartData ( string result ) {
            dynamic json = ( dynamic ) DynamicJson.Parse( result );

            if ( json.error() ) {
                Error = json.error;
                return;
            }

            dynamic [] json2 = ( dynamic[] ) DynamicJson.Parse( result );
            ChartData = new List<string[]>();



            foreach ( var item in json2 ) {
                ChartData.Add(
                    new string[]{
                        item.close.ToString( new CultureInfo( "en-us" ) ),
                        HelperLibrary.Convert.DateTime.FromUnixTime( ( long ) item.date ).ToString(),
                        item.high.ToString( new CultureInfo( "en-us" ) ),
                        item.low.ToString( new CultureInfo( "en-us" ) ),
                        item.open.ToString( new CultureInfo( "en-us" ) ),
                        item.quoteVolume.ToString( new CultureInfo( "en-us" ) ),
                        item.volume.ToString( new CultureInfo( "en-us" ) ),
                        item.weightedAverage.ToString( new CultureInfo( "en-us" ) ),

                    }
                );

            }

        }

        public static void ReturnCurrencies () {
            if ( !is_ReturnCurrencies_done ) {
                return;
            }
            is_ReturnCurrencies_done = false;

            Public_Query_Async( "returnCurrencies" );
        }
        private static void _ReturnCurrencies ( string result ) {
            dynamic j = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;

            if ( j.error() ) {
                Error = j.error;
                return;
            }

            dynamic [] json = ( dynamic[] ) DynamicJson.Parse( result );
            Currencies = new List<string[]>();

            foreach ( var item in json ) {
                if ( item.Key == "item" ) {
                    Currencies.Add(
                        new string[]{
                            "1CR",
                            ( ( int ) item.Value.delisted ).ToString( new CultureInfo( "en-us" ) ),
                            ( ( int ) item.Value.disabled ).ToString( new CultureInfo( "en-us" ) ),
                            ( ( int ) item.Value.maxDailyWithdrawal ).ToString( new CultureInfo( "en-us" ) ),
                            ( ( int ) item.Value.minConf ).ToString( new CultureInfo( "en-us" ) ),
                            ( ( int ) item.Value.txFee ).ToString( new CultureInfo( "en-us" ) ),
                        }
                    );


                } else {
                    Currencies.Add(
                        new string[]{
                            item.Key,
                            ( ( int ) item.Value.delisted ).ToString( new CultureInfo( "en-us" ) ),
                            ( ( int ) item.Value.disabled ).ToString( new CultureInfo( "en-us" ) ),
                            ( ( int ) item.Value.maxDailyWithdrawal ).ToString( new CultureInfo( "en-us" ) ),
                            ( ( int ) item.Value.minConf ).ToString( new CultureInfo( "en-us" ) ),
                            ( ( int ) item.Value.txFee ).ToString( new CultureInfo( "en-us" ) ),
                        }
                    );


                }

            }


        }

        public static void ReturnBalances () {
            if ( !is_ReturnBalances_done ) {
                return;
            }
            is_ReturnBalances_done = false;

            Private_Query_Async( "returnBalances" );

        }
        private static void _ReturnBalances ( string result ) {
            dynamic j = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;

            if ( j.error() ) {
                Error = j.error;
                return;
            }

            dynamic [] json = ( dynamic[] ) DynamicJson.Parse( result );
            Balances = new List<string[]>();

            foreach ( var item in json ) {
                Balances.Add(
                    new string[] { 
                        item.Key, 
                        item.Value 
                    }
                );
            }

        }

        public static void ReturnCompleteBalances () {
            if ( !is_ReturnCompleteBalances_done ) {
                return;
            }
            is_ReturnCompleteBalances_done = false;

            Private_Query_Async( "returnCompleteBalances" );
        }
        private static void _ReturnCompleteBalances ( string result ) {
            dynamic j = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;

            if ( j.error() ) {
                Error = j.error;
                return;
            }

            dynamic [] json = ( dynamic[] ) DynamicJson.Parse( result );
            CompleteBalances = new List<string[]>();

            foreach ( var item in json ) {
                CompleteBalances.Add(
                    new string[] { 
                            item.Key,
                            item.Value.available,
                            item.Value.btcValue,
                            item.Value.onOrders
                        }
                    );
            }


        }

        public static void ReturnDepositAddresses () {
            if ( !is_ReturnDepositAddresses_done ) {
                return;
            }
            is_ReturnDepositAddresses_done = false;

            Private_Query_Async( "returnDepositAddresses" );
        }
        private static void _ReturnDepositAddresses ( string result ) {
            dynamic j = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;

            if ( j.error() ) {
                Error = j.error;
                return;
            }

            dynamic [] json = ( dynamic[] ) DynamicJson.Parse( result );
            DepositAddresses = new List<string[]>();

            foreach ( var item in json ) {
                DepositAddresses.Add( new string[] { item.Key, item.Value } );

            }

        }

        /// <summary>
        /// May return error
        /// </summary>
        /// <param name="currency"></param>
        public static void GenerateNewAddress ( string currency ) {
            if ( !is_GenerateNewAddress_done ) {
                return;
            }
            is_GenerateNewAddress_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currency"] = currency;

            Private_Query_Async( "generateNewAddress", parameters );
        }
        private static void _GenerateNewAddress ( string result ) {
            dynamic json = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;

            if ( json.error() ) {
                Error = json.error;

            } else {
                NewAddress = json.response;

            }


        }

        public static void ReturnDepositsWithdrawals ( long start, long end ) {
            if ( !is_ReturnDepositsWithdrawals_done ) {
                return;
            }

            is_ReturnDepositsWithdrawals_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["start"] = start;
            parameters["end"] = end;

            Private_Query_Async( "returnDepositsWithdrawals", parameters );

        }
        private static void _ReturnDepositsWithdrawals ( string result ) {
            dynamic json = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;

            if ( json.error() ) {
                Error = json.error;
                return;
            }


            Deposits = new List<string[]>();
            Withdrawals = new List<string[]>();

            foreach ( var item in json.deposits ) {
                Deposits.Add(
                    new string[]{
                        item.address,
                        item.amount,
                        item.confirmations.ToString( new CultureInfo( "en-us" ) ),
                        item.currency,
                        item.status,
                        HelperLibrary.Convert.DateTime.FromUnixTime(item.timestamp),
                        item.txid
                    }
                );
            }

            foreach ( var item in json.withdrawals ) {
                Withdrawals.Add(
                    new string[]{
                        item.address,
                        item.amount,
                        item.ipAddress,
                        item.currency,
                        item.status,
                        HelperLibrary.Convert.DateTime.FromUnixTime(item.timestamp),
                        item.withdrawalNumber
                    }
                );
            }


        }

        public static void ReturnOpenOrders ( string currencyPair ) {
            if ( !is_ReturnOpenOrders_done ) {
                return;
            }

            is_ReturnOpenOrders_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currencyPair"] = currencyPair;

            Private_Query_Async( "returnOpenOrders", parameters );
        }
        private static void _ReturnOpenOrders ( string result ) {
            dynamic json = ( dynamic ) DynamicJson.Parse( result );
            OpenOrders = new List<string[]>();
            Error = string.Empty;

            if ( json.error() ) {
                Error = json.error;
                return;
            }

            foreach ( var order in json ) {
                OpenOrders.Add( new string[] {
                        order.amount,
                        order.orderNumber,
                        order.rate,
                        order.total,
                        order.type                               
                    }
                );

            }



        }

        public static void ReturnTradeHistory_my ( string currencyPair, long startDate, long endDate ) {
            if ( !is_ReturnTradeHistory_my_done ) {
                return;
            }

            if ( currencyPair == null ) {
                return;
            }
            is_ReturnTradeHistory_my_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currencyPair"] = currencyPair;
            parameters["start"] = startDate;
            parameters["end"] = endDate;

            Private_Query_Async( "returnTradeHistory", parameters );

        }
        private static void _ReturnTradeHistory_my ( string result ) {
            dynamic json = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;
            TradeHistory_my = new List<string[]>();

            if ( json.error() ) {
                Error = json.error;
                return;
            }


            foreach ( var trade in json ) {
                TradeHistory_my.Add( new string[] {
                        trade.amount,
                        HelperLibrary.Convert.DateTime.getDateTimeFromJsonString( trade.date ),
                        trade.orderNumber,
                        trade.rate,
                        trade.total,
                        trade.type                               
                    }
                );

            }



        }

        /// <summary>
        /// May return error
        /// </summary>
        /// <param name="currencyPair"></param>
        /// <param name="rate"></param>
        /// <param name="amount"></param>
        public static void Buy ( string currencyPair, double rate, double amount ) {
            if ( !is_ReturnTradeHistory_my_done ) {
                return;
            }
            is_ReturnTradeHistory_my_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currencyPair"] = currencyPair;
            parameters["rate"] = rate;
            parameters["amount"] = amount;

            Private_Query_Async( "buy", parameters );
        }
        private static void _Buy ( string result ) {
            dynamic json = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;

            if ( json.error() ) {
                Error = json.error;

            } else {
                OrderNumber = json.orderNumber;

            }

        }

        /// <summary>
        /// May return error
        /// </summary>
        /// <param name="currencyPair"></param>
        /// <param name="rate"></param>
        /// <param name="amount"></param>
        public static void Sell ( string currencyPair, double rate, double amount ) {
            if ( !is_ReturnTradeHistory_my_done ) {
                return;
            }
            is_ReturnTradeHistory_my_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currencyPair"] = currencyPair;
            parameters["rate"] = rate;
            parameters["amount"] = amount;

            Private_Query_Async( "buy", parameters );
        }
        private static void _Sell ( string result ) {
            dynamic json = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;

            if ( json.error() ) {
                Error = json.error;

            } else {
                OrderNumber = json.orderNumber;

            }

        }

        /// <summary>
        /// May return error
        /// </summary>
        /// <param name="currencyPair"></param>
        /// <param name="orderNumber"></param>
        public static void CancelOrder ( string currencyPair, int orderNumber ) {
            if ( !is_CancelOrder_done ) {
                return;
            }
            is_CancelOrder_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currencyPair"] = currencyPair;
            parameters["orderNumber"] = orderNumber;

            Private_Query_Async( "cancelOrder", parameters );

        }
        private static void _CancelOrder ( string result ) {
            dynamic json = ( dynamic ) DynamicJson.Parse( result );
            Error = string.Empty;
            Response = string.Empty;

            if ( json.error() ) {
                Error = json.error;

            } else {

                Response = json.success;

            }

        }

        /// <summary>
        /// May return error
        /// </summary>
        /// <param name="currency"></param>
        /// <param name="amount"></param>
        /// <param name="address"></param>
        /// <param name="paymentId"></param>
        public static void Withdraw ( string currency, double amount, string address, int paymentId = -1 ) {
            if ( !is_Withdraw_done ) {
                return;
            }
            is_Withdraw_done = false;

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters["currency"] = currency;
            parameters["amount"] = amount;
            parameters["address"] = address;
            if ( paymentId != -1 ) {
                parameters["paymentId"] = paymentId;

            }

            Private_Query_Async( "withdraw", parameters );
        }
        private static void _Withdraw ( string result ) {
            dynamic json = ( dynamic ) DynamicJson.Parse( result );
            Response = string.Empty;
            Error = string.Empty;

            if ( json.error() ) {
                Error = json.error;

            } else {
                Response = json.reponse;

            }


        }


        private static void Public_Query_Async ( string command, Dictionary<string, object> parameters = null ) {
            string cmd_line_argv = "command=" + command;

            if ( parameters != null ) {
                foreach ( var item in parameters ) {
                    cmd_line_argv += "&" + item.Key + "=" + item.Value;

                }
            }


            try {
                using ( var client = new WebClient() ) {
                    client.DownloadStringCompleted += client_public_DownloadStringCompleted;
                    client.DownloadStringAsync(
                        new Uri( "https://poloniex.com/public?" + cmd_line_argv ),
                        command
                    );

                }
            } catch ( Exception ex ) {
                MessageBox.Show( ex.Message, "Error" );

            }




        }
        private static void Private_Query_Async ( string command, Dictionary<string, object> parameters = null ) {
            string cmd_line_argv = "command=" + command + "&public=" + API_Public_Key + "&private=" + API_Private_Key;

            if ( parameters != null ) {
                foreach ( var item in parameters ) {
                    cmd_line_argv += "&" + item.Key + "=" + item.Value;

                }
            }


            try {
                using ( var client = new WebClient() ) {
                    client.DownloadStringCompleted += client_private_DownloadStringCompleted;
                    client.DownloadStringAsync(
                        new Uri( "http://localhost//nanobot//poloniex.com.php?" + cmd_line_argv ),
                        command
                    );

                }
            } catch ( Exception ex ) {
                MessageBox.Show( ex.Message, "Error" );

            }




        }

        private static void client_public_DownloadStringCompleted ( object sender, DownloadStringCompletedEventArgs e ) {
            string command = ( string ) e.UserState;
            string result = e.Result;

            switch ( command ) {
                case "returnTicker":
                    _ReturnTicker( result );
                    is_ReturnTicker_done = true;
                    is_FirstTime = false;
                    break;

                case "returnOrderBook":
                    _ReturnOrderBook( result );
                    is_ReturnOrderBook_done = true;
                    break;

                case "returnTradeHistory":
                    _ReturnTradeHistory( result );
                    is_ReturnTradeHistory_done = true;
                    break;

                case "returnChartData":
                    _ReturnChartData( result );
                    is_ReturnChartData_done = true;
                    break;

                case "returnCurrencies":
                    _ReturnCurrencies( result );
                    is_ReturnCurrencies_done = true;
                    break;

                default:
                    break;
            }



        }
        private static void client_private_DownloadStringCompleted ( object sender, DownloadStringCompletedEventArgs e ) {
            string command = ( string ) e.UserState;
            string result = e.Result;


            switch ( command ) {
                case "returnBalances":
                    _ReturnBalances( result );
                    is_ReturnBalances_done = true;
                    break;

                case "returnCompleteBalances":
                    _ReturnCompleteBalances( result );
                    is_ReturnCompleteBalances_done = true;
                    break;

                case "returnDepositAddresses":
                    _ReturnDepositAddresses( result );
                    is_ReturnDepositAddresses_done = true;
                    break;

                case "generateNewAddress":
                    _GenerateNewAddress( result );
                    is_GenerateNewAddress_done = true;
                    break;

                case "returnDepositsWithdrawals":
                    _ReturnDepositsWithdrawals( result );
                    is_ReturnDepositsWithdrawals_done = true;
                    break;

                case "returnOpenOrders":
                    _ReturnOpenOrders( result );
                    is_ReturnOpenOrders_done = true;
                    break;

                case "returnTradeHistory":
                    _ReturnTradeHistory_my( result );
                    is_ReturnTradeHistory_my_done = true;
                    break;

                case "buy":
                    _Buy( result );
                    is_Buy_done = true;
                    break;

                case "sell":
                    _Sell( result );
                    is_Sell_done = true;
                    break;

                case "cancelOrder":
                    _CancelOrder( result );
                    is_CancelOrder_done = true;
                    break;

                case "withdraw":
                    _Withdraw( result );
                    is_Withdraw_done = true;
                    break;

                default:
                    break;
            }


        }





    }
}
